﻿using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Text;
using System.IO;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Client;

namespace TransactionServer.CRMPlugin.CRM
{
    public enum uds_eventtypecode
    {
        Create = 752560000,
        Update = 752560001,
        Delete = 752560002,
        Assign = 752560003
    }

     

    public class GenerateEventFromCRM : IPlugin
    {
        private string secureConfiguration;
        private string unsecureConfiguration;
        public Dictionary<string, object> Connector;
        XmlSerializer serializer = new XmlSerializer(typeof(Event));

        private string system;
        private string user;

        private AttributeMetadata getAttrByName(EntityMetadata emd, string attrName)
        {
            AttributeMetadata result = null;

            foreach (AttributeMetadata amd in emd.Attributes)
            {
                if (amd.LogicalName == attrName)
                {
                    result = amd;
                }
            }

            return result;
        }

        public GenerateEventFromCRM(string unsecureConfiguration, string secureConfiguration)
        {
            this.secureConfiguration = secureConfiguration;
            this.unsecureConfiguration = unsecureConfiguration;

            if (!String.IsNullOrEmpty(unsecureConfiguration))
            {
                try
                {
                    var strings = unsecureConfiguration.Split(';');
                    system = strings[0];
                    if (strings.Length >= 2)
                    {
                        user = strings[1];
                    }
                }
                catch
                {
                    system = unsecureConfiguration;
                }
            }
        }

        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            if (!String.IsNullOrEmpty(user) && context.InitiatingUserId.Equals(new Guid(user)))
                return;

            Entity de = new Entity();
            Guid id = Guid.Empty;

            RetrieveEntityRequest rerq = new RetrieveEntityRequest();
            rerq.EntityFilters = EntityFilters.Attributes | EntityFilters.Relationships;
            rerq.LogicalName = context.PrimaryEntityName;

            EntityMetadata emd = ((RetrieveEntityResponse)service.Execute(rerq)).EntityMetadata;

            uds_eventtypecode code;

            if (context.MessageName == "Create")
            {
                de = (Entity)context.PostEntityImages["Image"];
                id = (Guid)context.OutputParameters["id"];

                code = uds_eventtypecode.Create;
            }
            else if (context.MessageName == "Update")
            {
                de = (Entity)context.PostEntityImages["Image"];
                id = de.Id;

                code = uds_eventtypecode.Update;
            }
            else if (context.MessageName == "Delete")
            {
                EntityReference mon = (EntityReference)context.InputParameters["Target"];
                de = new Entity();
                de.LogicalName = context.PrimaryEntityName;
                id = mon.Id;

                code = uds_eventtypecode.Delete;
            }
            else if (context.MessageName == "Assign")
            {
                EntityReference mon = (EntityReference)context.InputParameters["Target"];

                de = (Entity)context.PostEntityImages["Image"];
                EntityReference assignee = (EntityReference)context.InputParameters["Assignee"];
                de["ownerid"] =  new EntityReference("systemuser", assignee.Id);

                id = mon.Id;

                code = uds_eventtypecode.Assign;
            }
            else
            {
                return;
            }

            Entity_ ent = new Entity_();
            ent.System = system;
            ent.Name = de.LogicalName;
            ent.Id = id.ToString();

            foreach (KeyValuePair<string, object> prop in de.Attributes)
            {
                AttributeMetadata amd = getAttrByName(emd, prop.Key);

                if (amd != null)
                {
                    switch (amd.AttributeType.Value)
                    {
                        case AttributeTypeCode.Boolean:
                            ent.Add(prop.Key, (bool)prop.Value);
                            break;
                        case AttributeTypeCode.CalendarRules:
                            break;
                        case AttributeTypeCode.Customer:
                            ent.Add(prop.Key, ((EntityReference)prop.Value).Id);
                            break;
                        case AttributeTypeCode.DateTime:
                            ent.Add(prop.Key, ((DateTime)prop.Value).ToLocalTime());
                            break;
                        case AttributeTypeCode.Decimal:
                            ent.Add(prop.Key, (Decimal)prop.Value);
                            break;
                        case AttributeTypeCode.Double:
                            ent.Add(prop.Key, (Double)prop.Value);
                            break;
                        case AttributeTypeCode.Integer:
                            ent.Add(prop.Key, (int)prop.Value);
                            break;
                        case AttributeTypeCode.Lookup:
                            ent.Add(prop.Key, ((EntityReference)prop.Value).Id);
                            break;
                        case AttributeTypeCode.Memo:
                            ent.Add(prop.Key, (string)prop.Value);
                            break;
                        case AttributeTypeCode.Money:
                            ent.Add(prop.Key, ((Money)prop.Value).Value);
                            break;
                        case AttributeTypeCode.Owner:
                            ent.Add(prop.Key, ((EntityReference)prop.Value).Id);
                            break;
                        case AttributeTypeCode.PartyList:
                            break;
                        case AttributeTypeCode.Picklist:
                            ent.Add(prop.Key, ((OptionSetValue)prop.Value).Value);
                            break;
                        case AttributeTypeCode.Uniqueidentifier:
                            ent.Add(prop.Key, (Guid)prop.Value);
                            break;
                        case AttributeTypeCode.State:
                            ent.Add(prop.Key, ((OptionSetValue)prop.Value).Value);
                            break;
                        case AttributeTypeCode.Status:
                            ent.Add(prop.Key, ((OptionSetValue)prop.Value).Value);
                            break;
                        case AttributeTypeCode.String:
                            ent.Add(prop.Key, (string)prop.Value);
                            break;
                        case AttributeTypeCode.Virtual:
                            break;
                        default:
                            break;
                    }
                }
            }

            Event evnt = new Event
            {
                Entity = ent,
                MessageName = context.MessageName,
                OccuredOn = DateTime.Now
            };

            Connector = new Dictionary<string, object>();
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            serializer.Serialize(sw, evnt);

            //create new object of uds_entity
            OrganizationServiceContext orgContext = new OrganizationServiceContext(service);

            Entity uds_integrationevent = new Entity("uds_integrationevent");
            uds_integrationevent["uds_name"] = String.Format("{0} : {1}", evnt.MessageName, ent.Name);
            uds_integrationevent["uds_entity"] = ent.Name;
            uds_integrationevent["uds_entityid"] = ent.Id;
            uds_integrationevent["uds_event"] = sb.ToString();

            OptionSetValue op;
            switch (code)
            {
                case uds_eventtypecode.Create:
                    op = new OptionSetValue(752560000);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
                case uds_eventtypecode.Update:
                    op = new OptionSetValue(752560001);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
                case uds_eventtypecode.Delete:
                    op = new OptionSetValue(752560002);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
                case uds_eventtypecode.Assign:
                    op = new OptionSetValue(752560003);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
                default:
                    break;
            }
            orgContext.AddObject(uds_integrationevent);
            orgContext.SaveChanges();
        }
    }
}
